package middleware

import (
	"AccessAdmin/internal/model"
	"AccessAdmin/internal/service"
	"AccessAdmin/utility/response"
	"AccessAdmin/utility/utils"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"log"
	"net/http"
)

type sMiddleware struct {
	LoginUrl string // 登录路由地址
}

func init() {
	service.RegisterMiddleware(New())
}

func New() *sMiddleware {
	return &sMiddleware{
		LoginUrl: "/admin/login",
	}
}

// ResponseHandler 返回处理中间件
func (s *sMiddleware) ResponseHandler(r *ghttp.Request) {
	r.Middleware.Next()

	// 如果已经有返回内容，那么该中间件什么也不做
	if r.Response.BufferLength() > 0 {
		return
	}

	var (
		err             = r.GetError()
		res             = r.GetHandlerResponse()
		code gcode.Code = gcode.CodeOK
	)
	if err != nil {
		code = gerror.Code(err)
		if code == gcode.CodeNil {
			code = gcode.CodeInternalError
		}
		r.Response.ClearBuffer()
		if r.IsAjaxRequest() {
			response.JsonExit(r, code.Code(), err.Error())
		} else {
			service.View().Render500(r.Context(), model.View{
				Error: err.Error(),
			})
		}
	} else {
		if r.IsAjaxRequest() {
			response.JsonExit(r, code.Code(), "操作成功", res)
		} else {
			// 什么都不做，业务API自行处理模板渲染的成功逻辑。
		}
	}
}

// Ctx 自定义上下文对象
func (s *sMiddleware) Ctx(r *ghttp.Request) {
	// 初始化，务必最开始执行
	customCtx := &model.Context{
		Session: r.Session,
		Data:    make(g.Map),
	}
	service.BizCtx().Init(r, customCtx)
	if userEntity := service.Session().GetUser(r.Context()); userEntity.Id > 0 {
		customCtx.User = userEntity
	}

	if menus, _ := service.Session().GetMenus(r.Context()); len(menus) > 0 {
		customCtx.Menu = menus
	}

	if routes, _ := service.Session().GetRoutes(r.Context()); len(routes) > 0 {
		customCtx.Data["routes"], _ = gjson.EncodeString(routes)
	}

	// 将自定义的上下文对象传递到模板变量中使用
	r.Assigns(g.Map{
		"Context": customCtx,
	})
	// 执行下一步请求逻辑
	r.Middleware.Next()
}

func (s *sMiddleware) CORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

func ErrorHandler(r *ghttp.Request) {
	r.Middleware.Next()
	if err := r.GetError(); err != nil {
		// 记录到自定义错误日志文件
		g.Log("exception").Error(r.Context(), err)
		//返回固定的友好信息
		r.Response.ClearBuffer()
		if response.IsRestfulRequest(r) {
			response.Error(r)
		} else {
			service.View().Render500(r.Context(), model.View{
				Error: err.Error(),
			})
		}
	}
}

// Auth 前台系统权限控制，用户必须登录才能访问
func (s *sMiddleware) Auth(r *ghttp.Request) {
	user := service.Session().GetUser(r.Context())
	if user.Id == 0 {
		// 只有GET请求才支持保存当前URL，以便后续登录后再跳转回来。
		if r.Method == "GET" {
			_ = service.Session().SetLoginReferer(r.Context(), r.GetUrl())
		}
		r.Response.RedirectTo(s.LoginUrl)
	}
	if !service.User().IsAdmin(r.Context(), user.Id) {
		var commonRoutes []string
		g.Cfg().MustGet(r.Context(), `setting.commonRoutes`).Scan(&commonRoutes)
		e := service.Casbin().CasBin(r.Context())
		ok, _ := e.Enforce(user.Username, r.URL.Path, r.Method)
		if !ok && !utils.IsContainStr(commonRoutes, r.URL.Path) {
			if r.IsAjaxRequest() {
				response.JsonExit(r, http.StatusForbidden, "哎呦，你没有权限哦！")
			} else {
				r.Response.WriteHeader(http.StatusForbidden)
				r.Exit()
			}
		} else {
			log.Println("Check successfully")
			r.Middleware.Next()
		}
	} else {
		r.Middleware.Next()
	}
}
